package com.ryan.encrypttool.business.auth.config;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import com.ryan.encrypttool.common.annotation.FuzzyParam;

import lombok.extern.slf4j.Slf4j;

/**
 * @program encrypt-tool
 * @description
 * @author ryan
 * @create 2024-03-08 19:25
 **/
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 业务代码
        Method method = invocation.getMethod();
        // 拦截sql
        Object[] args = invocation.getArgs();
        MappedStatement statement = (MappedStatement)args[0];

        // 获取 SQL
        SqlCommandType sqlCommandType = statement.getSqlCommandType();
        if (SqlCommandType.SELECT.equals(sqlCommandType)) {
            HashMap paramMap = (HashMap)args[1];
            paramMap.forEach((k, v) -> {
                if ("pm".equals(k)) {

                    Field[] declaredFields = v.getClass().getDeclaredFields();
                    for (Field declaredField : declaredFields) {
                        boolean annotationPresent = declaredField.isAnnotationPresent(FuzzyParam.class);
                        if (annotationPresent) {
                            declaredField.setAccessible(true);
                            try {
                                Object param = declaredField.get(v);
                                String finalValue = escapeSqlSpecialChar(param);
                                declaredField.set(v, finalValue);
                            } catch (IllegalAccessException e) {
                                throw new RuntimeException(e);
                            }

                        }

                    }

                }
            });
        }

        log.info("开始拦截 select 请求");
        return invocation.proceed();
    }

    public String escapeSqlSpecialChar(Object str) {
        return ((String)str).trim().replaceAll("\\s", "").replace("\\", "\\\\\\\\").replace("_", "\\_")
            .replace("\'", "\\'").replace("%", "\\%").replace("*", "\\*");
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }

}
